/****************************************************************************
 *
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

import QtQuick                  2.11
import QtQuick.Controls         2.4
import QtQuick.Layouts          1.11
import QtQuick.Dialogs          1.3
import QtQuick.Controls.Styles  1.4
import QtLocation               5.3
import QtPositioning            5.3




Item {
    id:             offlineMapView
    anchors.fill:   parent

    property string mapType:           "Gaode Road"
    property var    _currentSelection:  null
    readonly property real sliderTouchArea: 10 *5
    property bool   isMapInteractive:   false

    property var    savedCenter:        undefined
    property real   savedZoom:          3
    property string savedMapType:       ""
    property bool   _defaultSet:        offlineMapView && offlineMapView._currentSelection && offlineMapView._currentSelection.defaultSet

    Component.onCompleted: {
            mapEngineManager.loadTileSets()
            updateMap()
            savedCenter = _map.toCoordinate(Qt.point(_map.width / 2, _map.height / 2), false /* clipToViewPort */)
            console.log("..............................1")
        }

    Connections {
        target:mapEngineManager
        function onTileSetsChanged() {
            console.log("..............................2")
            setName.text = mapEngineManager.getUniqueName()
            console.log("mapEngineManager.getUniqueName()"+mapEngineManager.getUniqueName())
        }

    }

    function updateMap() {
        console.log("updateMap"+_map.supportedMapTypes.length)
        for (var i = 0; i < _map.supportedMapTypes.length; i++) {
            if (mapType === _map.supportedMapTypes[i].name) {
                _map.activeMapType = _map.supportedMapTypes[i]
                console.log("updateMap"+_map.activeMapType)
                handleChanges()
                return
            }
        }
    }

    function showList() {
        //_exporTiles.visible = false
        isMapInteractive = false
        _map.visible = false
        _tileSetList.visible = true
        newSetRect.visible = false
        infoView.visible = false
        //addNewSetView.visible = false
        mapEngineManager.resetAction();
    }

    function addNewSet() {
        isMapInteractive = true
        mapType = "Gaode" + " " + "Road"
        resetMapToDefaults()
        handleChanges()
        _map.visible = true
        console.log(",,,,,,,,,,,,,")
        _tileSetList.visible = false
        newSetRect.visible = true
        infoView.visible = false
       // _exporTiles.visible = false
       // addNewSetView.visible = true
    }

    function resetMapToDefaults() {
            _map.center = QtPositioning.coordinate(30.67, 104.06)
            _map.zoomLevel = 10
        }

    function handleChanges() {
        if(isMapInteractive) {
            var xl = 0
            var yl = 0
            var xr = _map.width.toFixed(0) - 1  // Must be within boundaries of visible map
            var yr = _map.height.toFixed(0) - 1 // Must be within boundaries of visible map
            var c0 = _map.toCoordinate(Qt.point(xl, yl), false /* clipToViewPort */)
            var c1 = _map.toCoordinate(Qt.point(xr, yr), false /* clipToViewPort */)
            console.log("handleChanges"+mapType)
            mapEngineManager.updateForCurrentView(c0.longitude, c0.latitude, c1.longitude, c1.latitude, sliderMinZoom.value, sliderMaxZoom.value, mapType)
        }
    }

    function showInfo() {
        isMapInteractive = false
        if(_currentSelection && !offlineMapView._currentSelection.deleting) {
            enterInfoView()
            console.log("enterInfoView()")
        } else{
            showList()
            console.log("showList()")
        }


    }


    function toRadian(deg) {
            return deg * Math.PI / 180
    }

    function toDegree(rad) {
        return rad * 180 / Math.PI
    }
    function midPoint(lat1, lat2, lon1, lon2) {
            var dLon = toRadian(lon2 - lon1);
            lat1 = toRadian(lat1);
            lat2 = toRadian(lat2);
            lon1 = toRadian(lon1);
            var Bx = Math.cos(lat2) * Math.cos(dLon);
            var By = Math.cos(lat2) * Math.sin(dLon);
            var lat3 = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By));
            var lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx);
            return QtPositioning.coordinate(toDegree(lat3), toDegree(lon3))
        }

    function enterInfoView() {
        _map.visible = true
        isMapInteractive = false
        savedCenter = _map.toCoordinate(Qt.point(_map.width / 2, _map.height / 2), false /* clipToViewPort */)
        savedZoom = _map.zoomLevel
        savedMapType = mapType
        if(!offlineMapView._currentSelection.defaultSet) {
            mapType = offlineMapView._currentSelection.mapTypeStr
            _map.center = midPoint(offlineMapView._currentSelection.topleftLat, offlineMapView._currentSelection.bottomRightLat, offlineMapView._currentSelection.topleftLon, offlineMapView._currentSelection.bottomRightLon)
            //-- Delineate Set Region
            var x0 = offlineMapView._currentSelection.topleftLon
            var x1 = offlineMapView._currentSelection.bottomRightLon
            var y0 = offlineMapView._currentSelection.topleftLat
            var y1 = offlineMapView._currentSelection.bottomRightLat
            mapBoundary.topLeft     = QtPositioning.coordinate(y0, x0)
            mapBoundary.bottomRight = QtPositioning.coordinate(y1, x1)
            mapBoundary.visible = true
            // Some times, for whatever reason, the bounding box is correct (around ETH for instance), but the rectangle is drawn across the planet.
            // When that happens, the "_map.fitViewportToMapItems()" below makes the map to zoom to the entire earth.
            //console.log("Map boundary: " + mapBoundary.topLeft + " " + mapBoundary.bottomRight)
            _map.fitViewportToMapItems()
        }
        _tileSetList.visible = false
        //addNewSetView.visible = false
        infoView.visible = true
    }

    function leaveInfoView() {
            mapBoundary.visible = false
            _map.center = savedCenter
            _map.zoomLevel = savedZoom
            mapType = savedMapType
        }
    Item {
        anchors.fill:       parent
        FlightMap {
            id:                         _map
            anchors.fill:               parent
            visible:                    false
            gesture.flickDeceleration:  3000
            mapName:                    "OfflineMap"
            center: QtPositioning.coordinate(30.67, 104.06)
            //property bool isSatelliteMap: activeMapType.name.indexOf("Satellite") > -1 || activeMapType.name.indexOf("Hybrid") > -1

            MapRectangle {
                id:             mapBoundary
                border.width:   2
                border.color:   "red"
                color:          Qt.rgba(1,0,0,0.05)
                smooth:         true
                antialiasing:   true
            }

            //Component.onCompleted: resetMapToDefaults()

            //onCenterChanged:    handleChanges()
            //onZoomLevelChanged: handleChanges()
            //onWidthChanged:     handleChanges()
            //onHeightChanged:    handleChanges()

            // Used to make pinch zoom work
            MouseArea {
                anchors.fill: parent
            }

            // MapScale {
            //     anchors.leftMargin:     20 / 2
            //     anchors.bottomMargin:   anchors.leftMargin
            //     anchors.left:           parent.left
            //     anchors.bottom:         parent.bottom
            //     mapControl:             _map
            //     buttonsOnLeft:          true
            // }
        } // Map
        Flickable {
            id:                 _tileSetList
            clip:               true
            anchors.margins:    10
            anchors.top:        parent.top
            anchors.bottom:     parent.bottom//_listButtonRow.top
            anchors.left:       parent.left
            anchors.right:      parent.right
            contentHeight:      _cacheList.height
            ButtonGroup {
                id:             buttonGroup
                buttons:        _cacheList.children
            }
            Column {
                id:             _cacheList
                width:          Math.min(_tileSetList.width, (10  * 50).toFixed(0))
                spacing:        10
                anchors.horizontalCenter: parent.horizontalCenter
                OfflineMapButton {
                    id:             firstButton
                    text:           qsTr("Add New Set")
                    width:          _cacheList.width
                    height:        30
                    currentSet:     _currentSelection
                    onClicked: {
                        offlineMapView._currentSelection = null
                        checked = true
                        addNewSet()
                    }
                }
                Repeater {
                    model: mapEngineManager.tileSets
                    delegate: OfflineMapButton {
                        text:           object.name
                        size:           object.downloadStatus
                        tiles:          object.totalTileCount
                        complete:       object.complete
                        width:          firstButton.width
                        height:         50
                        currentSet:     _currentSelection
                        tileSet:        object
                        onClicked: {
                            offlineMapView._currentSelection = object
                            checked = true
                            showInfo()
                        }
                    }
                }
            }
        }

        //-- Add new set dialog
        Rectangle {
            id:newSetRect
            anchors.margins:    20
            anchors.verticalCenter: parent.verticalCenter
            anchors.right:      parent.right
            visible:            false
            width:              200
            height:             400
            color:              "#000000"
            radius:             20 * 0.5

            //-- Eat mouse events

            MouseArea {
                anchors.fill: parent
                preventStealing:true
                hoverEnabled:   true
                onWheel:        { wheel.accepted = true; }
                onPressed:      { mouse.accepted = true; }
                onReleased:     { mouse.accepted = true; }
            }

            Label {
                id:                 addNewSetLabel
                anchors.margins:    30 / 2
                anchors.top:        parent.top
                anchors.left:       parent.left
                anchors.right:      parent.right
                wrapMode:           Text.WordWrap
                text:               qsTr("Add New Set")
                font.pointSize:    16
                color:          "#ffffff"
                horizontalAlignment: Text.AlignHCenter
            }

            Flickable {
                id:                     addNewSetFlickable
                anchors.leftMargin:     20
                anchors.rightMargin:    anchors.leftMargin
                anchors.topMargin:      20 / 3
                anchors.bottomMargin:   anchors.topMargin
                anchors.top:            addNewSetLabel.bottom
                anchors.left:           parent.left
                anchors.right:          parent.right
                anchors.bottom:         parent.bottom
                clip:                   true
                contentHeight:          addNewSetColumn.height

                Column {
                    id:                 addNewSetColumn
                    anchors.left:       parent.left
                    anchors.right:      parent.right
                    spacing:            10

                    Column {
                        spacing:            5
                        anchors.left:       parent.left
                        anchors.right:      parent.right
                        Label { text: qsTr("Name:")
                            color:          "#ffffff" }
                        TextField {
                            id:             setName
                            anchors.left:   parent.left
                            anchors.right:  parent.right
                        }
                    }

                    Column {
                        spacing:           5
                        anchors.left:       parent.left
                        anchors.right:      parent.right
                        Label {
                            text:       qsTr("Map type:")
                            color:          "#ffffff"
                        }
                        ComboBox {
                            id:             mapCombo
                            anchors.left:   parent.left
                            anchors.right:  parent.right
                            model:          mapEngineManager.mapList
                            onActivated: {
                                mapType = textAt(index)
                            }
                            Component.onCompleted: {
                                var index = mapCombo.find(mapType)
                                if (index === -1) {
                                    console.warn("Active map name not in combo", mapType)
                                } else {
                                    mapCombo.currentIndex = index
                                }
                            }
                        }
                    }

                    Rectangle {
                        anchors.left:   parent.left
                        anchors.right:  parent.right
                        height:         zoomColumn.height + 30 * 0.5
                        color:          "#555555"
                        border.color:   "#ffffff"
                        radius:         20 * 0.5

                        Column {
                            id:                 zoomColumn
                            spacing:            10
                            anchors.margins:    5
                            anchors.top:        parent.top
                            anchors.left:       parent.left
                            anchors.right:      parent.right

                            Label {
                                text:           qsTr("Min/Max Zoom Levels")
                                font.pointSize: 12
                                anchors.horizontalCenter: parent.horizontalCenter
                            }

                            Slider {
                                id:                         sliderMinZoom
                                anchors.left:               parent.left
                                anchors.right:              parent.right
                                height:                     40
                                from:                       3
                                to:                         20
                                stepSize:                   1
                                live:                       true
                                property bool _updateSetting: false
                                Component.onCompleted: {
                                    sliderMinZoom.value = 3
                                    //_updateSetting = true
                                }
                                onValueChanged: {
                                    if(sliderMinZoom.value > sliderMaxZoom.value) {
                                        sliderMaxZoom.value = sliderMinZoom.value
                                    }
                                    handleChanges()
                                }
                                handle: Rectangle {
                                    x: sliderMinZoom.leftPadding + sliderMinZoom.visualPosition  * (sliderMinZoom.availableWidth - width)
                                    y: sliderMinZoom.topPadding  + sliderMinZoom.availableHeight * 0.5 - height * 0.5
                                    implicitWidth:  30
                                    implicitHeight: 30
                                    radius:         30 * 0.5
                                    color:          "#000000"
                                    border.width:   1
                                    border.color:   "#555555"
                                    Label {
                                        text:               sliderMinZoom.value
                                        anchors.centerIn:   parent
                                        font.pointSize:     12
                                        color:              "#ffffff"
                                    }
                                }
                            } // Slider - min zoom

                            Slider {
                                id:                         sliderMaxZoom
                                anchors.left:               parent.left
                                anchors.right:              parent.right
                                height:                     40
                                from:                       3
                                to:                         20
                                stepSize:                   1
                                live:                       true
                                property bool _updateSetting: false
                                Component.onCompleted: {
                                    sliderMaxZoom.value = 20
                                    _updateSetting = true
                                }
                                onValueChanged: {
                                    if(sliderMaxZoom.value < sliderMinZoom.value) {
                                        sliderMinZoom.value = sliderMaxZoom.value
                                    }

                                    handleChanges()
                                }
                                handle: Rectangle {
                                    x: sliderMaxZoom.leftPadding + sliderMaxZoom.visualPosition  * (sliderMaxZoom.availableWidth - width)
                                    y: sliderMaxZoom.topPadding  + sliderMaxZoom.availableHeight * 0.5 - height * 0.5
                                    implicitWidth:  30
                                    implicitHeight: 30
                                    radius:         30 * 0.5
                                    color:          "#000000"
                                    border.width:   1
                                    border.color:   "#555555"
                                    Label {
                                        text:               sliderMaxZoom.value
                                        anchors.centerIn:   parent
                                        font.pointSize:     12
                                        color:              "#ffffff"
                                    }
                                }
                            } // Slider - max zoom

                            GridLayout {
                                columns:    2
                                rowSpacing: 30 * 0.5
                                Label {
                                    text:           qsTr("Tile Count:")
                                    font.pointSize: 12
                                }
                                Label {
                                    text:            mapEngineManager.tileCountStr
                                    font.pointSize: 12
                                }

                                Label {
                                    text:           qsTr("Est Size:")
                                    font.pointSize: 12
                                }
                                Label {
                                    text:           mapEngineManager.tileSizeStr
                                    font.pointSize: 12
                                }
                            }
                        } // Column - Zoom info
                    } // Rectangle - Zoom info

                    Label {
                        text:       qsTr("Too many tiles")
                        visible:    true
                        color:      "white"
                        anchors.horizontalCenter: parent.horizontalCenter
                    }

                    Row {
                        id: addButtonRow
                        spacing: 20
                        anchors.horizontalCenter: parent.horizontalCenter
                        Button {
                            text:       qsTr("Download")
                            width:      (addNewSetColumn.width * 0.5) - (addButtonRow.spacing * 0.5)
                            enabled:   true
                            onClicked: {
                                if(mapEngineManager.findName(setName.text)) {
                                    duplicateName.visible = true
                                } else {
                                    mapEngineManager.startDownload(setName.text, mapType);
                                    //console.log(setName.text+mapType)
                                    showList()
                                }
                            }
                        }
                        Button {
                            text:       qsTr("Cancel")
                            width:      (addNewSetColumn.width * 0.5) - (addButtonRow.spacing * 0.5)
                            onClicked: {
                                showList()
                            }
                        }
                    }

                } // Column
            } // QGCFlickable
        } // Rectangle - Add new set dialog


        //-----------------------------------------------------------------
        //-- Show Set Info
        Rectangle {
            id:                 infoView
            anchors.margins:    ScreenTools.defaultFontPixelHeight
            anchors.right:      parent.right
            anchors.verticalCenter: parent.verticalCenter
            width:              tileInfoColumn.width  + (10  * 2)
            height:             tileInfoColumn.height + (10 * 2)
            color:              "#000000"
            radius:             10 * 0.5
            visible:            false

            property bool       _extraButton: {
                if(!offlineMapView._currentSelection)
                    return false;
                var curSel = offlineMapView._currentSelection;
                return !_defaultSet && ((!curSel.complete && !curSel.downloading) || (!curSel.complete && curSel.downloading));
            }

            property real       _labelWidth:    10 * 10
            property real       _valueWidth:    10 * 14
            Column {
                id:                 tileInfoColumn
                anchors.margins:    10
                spacing:            10
                anchors.centerIn:   parent
                Label {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    wrapMode:       Text.WordWrap
                    text:           offlineMapView._currentSelection ? offlineMapView._currentSelection.name : ""
                    font.pointSize: 12
                    horizontalAlignment: Text.AlignHCenter
                    visible:        _defaultSet
                    color: "#ffffff"
                }
                TextField {
                    id:             editSetName
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    visible:        !_defaultSet
                    text:           offlineMapView._currentSelection ? offlineMapView._currentSelection.name : ""
                }
                Label {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    wrapMode:       Text.WordWrap
                    color: "#ffffff"
                    text: {
                        if(offlineMapView._currentSelection) {
                            if(offlineMapView._currentSelection.defaultSet)
                                return qsTr("System Wide Tile Cache");
                            else
                                return "(" + offlineMapView._currentSelection.mapTypeStr + ")"
                        } else
                            return "";
                    }
                    horizontalAlignment: Text.AlignHCenter
                }
                //-- Tile Sets
                Row {
                    spacing:    10
                    anchors.horizontalCenter: parent.horizontalCenter
                    visible:    !_defaultSet
                    Label {  text: qsTr("Zoom Levels:"); width: infoView._labelWidth; color: "#ffffff"}
                    Label {  text: offlineMapView._currentSelection ? (offlineMapView._currentSelection.minZoom + " - " + offlineMapView._currentSelection.maxZoom) : ""; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth;color: "#ffffff" }
                }
                Row {
                    spacing:    10
                    anchors.horizontalCenter: parent.horizontalCenter
                    visible:    !_defaultSet
                    Label {  text: qsTr("Total:"); width: infoView._labelWidth; color: "#ffffff"}
                    Label {  text: (offlineMapView._currentSelection ? offlineMapView._currentSelection.totalTileCountStr : "") + " (" + (offlineMapView._currentSelection ? offlineMapView._currentSelection.totalTilesSizeStr : "") + ")"; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth;color: "#ffffff" }
                }
                Row {
                    spacing:    10
                    anchors.horizontalCenter: parent.horizontalCenter
                    visible:    offlineMapView && offlineMapView._currentSelection && !_defaultSet && offlineMapView._currentSelection.uniqueTileCount > 0
                    Label {  text: qsTr("Unique:"); width: infoView._labelWidth; color: "#ffffff"}
                    Label {  text: (offlineMapView._currentSelection ? offlineMapView._currentSelection.uniqueTileCountStr : "") + " (" + (offlineMapView._currentSelection ? offlineMapView._currentSelection.uniqueTileSizeStr : "") + ")"; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth;color: "#ffffff" }
                }

                Row {
                    spacing:    10
                    anchors.horizontalCenter: parent.horizontalCenter
                    visible:    offlineMapView && offlineMapView._currentSelection && !_defaultSet && !offlineMapView._currentSelection.complete
                    Label {  text: qsTr("Downloaded:"); width: infoView._labelWidth; color: "#ffffff"}
                    Label {  text: (offlineMapView._currentSelection ? offlineMapView._currentSelection.savedTileCountStr : "") + " (" + (offlineMapView._currentSelection ? offlineMapView._currentSelection.savedTileSizeStr : "") + ")"; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth; color: "#ffffff"}
                }
                Row {
                    spacing:    10
                    anchors.horizontalCenter: parent.horizontalCenter
                    visible:    offlineMapView && offlineMapView._currentSelection && !_defaultSet && !offlineMapView._currentSelection.complete && offlineMapView._currentSelection.errorCount > 0
                    Label {  text: qsTr("Error Count:"); width: infoView._labelWidth; color: "#ffffff"}
                    Label {  text: offlineMapView._currentSelection ? offlineMapView._currentSelection.errorCountStr : ""; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth;color: "#ffffff" }
                }
                //-- Default Tile Set
                Row {
                    spacing:    10
                    anchors.horizontalCenter: parent.horizontalCenter
                    visible:    _defaultSet
                    Label { text: qsTr("Size:"); width: infoView._labelWidth; color: "#ffffff"}
                    Label { text: offlineMapView._currentSelection ? offlineMapView._currentSelection.savedTileSizeStr  : ""; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth;color: "#ffffff" }
                }
                Row {
                    spacing:    10
                    anchors.horizontalCenter: parent.horizontalCenter
                    visible:    _defaultSet
                    Label { text: qsTr("Tile Count:"); width: infoView._labelWidth; color: "#ffffff"}
                    Label { text: offlineMapView._currentSelection ? offlineMapView._currentSelection.savedTileCountStr : ""; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth;color: "#ffffff" }
                }
                Row {
                    spacing:    10
                    anchors.horizontalCenter: parent.horizontalCenter
                    Button {
                        text:       qsTr("Resume Download")
                        visible:    offlineMapView._currentSelection && offlineMapView._currentSelection && !_defaultSet && (!offlineMapView._currentSelection.complete && !offlineMapView._currentSelection.downloading)
                        width:      10 * 16
                        onClicked: {
                            if(offlineMapView._currentSelection)
                                offlineMapView._currentSelection.resumeDownloadTask()
                        }
                    }
                    Button {
                        text:       qsTr("Cancel Download")
                        visible:    offlineMapView._currentSelection && offlineMapView._currentSelection && !_defaultSet && (!offlineMapView._currentSelection.complete && offlineMapView._currentSelection.downloading)
                        width:      10 * 16
                        onClicked: {
                            if(offlineMapView._currentSelection)
                                offlineMapView._currentSelection.cancelDownloadTask()
                        }
                    }
                    Button {
                        text:       qsTr("Delete")
                        width:      10 * (infoView._extraButton ? 6 : 10)
                        onClicked:  {
                            mapEngineManager.deleteTileSet(offlineMapView._currentSelection)
                            leaveInfoView()
                            showList()
                        }
                        enabled:    offlineMapView._currentSelection ? (offlineMapView._currentSelection.savedTileSize > 0) : false
                    }
                    Button {
                        text:       qsTr("Ok")
                        width:      10 * (infoView._extraButton ? 6 : 10)
                        visible:    !_defaultSet
                        enabled:    editSetName.text !== ""
                        onClicked: {
                            if(editSetName.text !== _currentSelection.name) {
                                mapEngineManager.renameTileSet(_currentSelection, editSetName.text)
                            }
                            leaveInfoView()
                            showList()
                        }
                    }
                    Button {
                        text:       _defaultSet ? qsTr("Close") : qsTr("Cancel")
                        width:      10 * (infoView._extraButton ? 6 : 10)
                        onClicked: {
                            leaveInfoView()
                            showList()
                        }
                    }
                }
            }
        } // Rectangle - infoView
    }

}
